package scu.maqiang.neuralnetwork;

import java.util.ArrayList;

import scu.maqiang.neuralnetwork.math.*;

/**
 * InputLayer类, 神经网络输入层
 * 该类继承自NeuralLayer类, 代表神经网络的输入层
 *
 * @author Alan de Souza, Fábio Soares
 * @version 0.1
 */
public class InputLayer extends NeuralLayer {

    /**
     * 构造函数
     *
     * @param numberofinputs 该层的输入个数, 也是神经网络的输入个数
     * @see InputLayer
     */
    public InputLayer(int numberofinputs) {
        //初妈化numberofinputs个输入神经元
        super(numberofinputs, new Linear(1));
        //由于该层是输入层, 该层之前没有神经元层
        previousLayer = null;
        //输入个数
        numberOfInputs = numberofinputs;
        init();
    }

    /**
     *
     * 设置神经网络输入层的下一层
     * @param layer 下一层神经元层
     * @see InputLayer
     */
    @Override
    public void setNextLayer(NeuralLayer layer) {
        nextLayer = layer;
        if (layer.previousLayer != this)
            layer.setPreviousLayer(this);
    }

    /**
     * setPreviousLayer
     * This method prevents any attempt to link this layer to a previous one,
     * provided that this should be the first layer
     *
     * @param layer dummy Neural Layer
     * @see InputLayer
     */
    @Override
    public void setPreviousLayer(NeuralLayer layer) {
        previousLayer = null;
    }

    /**
     * init
     * This method initializes all neurons of this layer
     *
     * @see InputLayer
     */
    @Override
    public void init() {
        for (int i = 0; i < numberOfInputs; i++) {
            this.setNeuron(i, new InputNeuron());
            this.getNeuron(i).init();
        }
    }

    /**
     * setInputs
     * This method feeds an array of real values into this layer's inputs
     *
     * @param inputs array of values to be fed into the layer's inputs
     * @see InputLayer
     */
    @Override
    public void setInputs(ArrayList<Double> inputs) {
        if (inputs.size() == numberOfInputs) {
            input = inputs;
        }
    }

    /**
     * calc
     * This method overrides the superclass calc because it just passes the
     * input values to the outputs, provided this is the input layer
     *
     * @see InputLayer
     */
    @Override
    public void calc() {
        if (input != null && getListOfNeurons() != null) {
            for (int i = 0; i < numberOfNeuronsInLayer; i++) {
                double[] firstInput = {this.input.get(i)};
                getNeuron(i).setInputs(firstInput);
                getNeuron(i).calc();
                try {
                    output.set(i, getNeuron(i).getOutput());
                } catch (IndexOutOfBoundsException iobe) {
                    output.add(getNeuron(i).getOutput());
                }
            }
        }
    }

}
